Skip to content

fix: deleted catalogs no longer flash back on home load (#71) - #125

Merged
ProdigyV21 merged 1 commit into
mainfrom
fix/catalog-delete-skeleton-flash
Apr 5, 2026
Merged

fix: deleted catalogs no longer flash back on home load (#71)#125
ProdigyV21 merged 1 commit into
mainfrom
fix/catalog-delete-skeleton-flash

Conversation

@ProdigyV21

Copy link
Copy Markdown
Owner

Summary

Closes #71 (and the duplicate #74 we already closed).

Users reported that deleting a catalog (e.g. "Trending in Anime", "New K-Dramas") showed a "removed" confirmation but the catalog reappeared a moment later on the home screen, even after restart. The reports included screenshots showing the catalog flashing back in during home loading.

Root cause

The persistence layer was already correct — removeCustomCatalog adds the id to a hidden set, ensurePreinstalledDefaults filters against it, cloud sync carries it both ways, and readCatalogsFromPrefs honors it when reading the full list.

But HomeViewModel.loadHomeData() (line 915-931) builds an "early skeleton" of loading rows before calling ensurePreinstalledDefaults, and it built that skeleton directly from mediaRepository.getDefaultCatalogConfigs() — the unfiltered list of all 26 preinstalled catalogs. So on every cold load and every subsequent loadHomeData() call where categories.isEmpty(), the user saw their deleted catalogs reappear as skeleton rows for 1-3 seconds until the real filtered list replaced them. On slow networks the flash lasted long enough that users believed the delete never took effect.

Fix

Before building the early skeleton, read the active-profile hidden set via the existing catalogRepository.getHiddenPreinstalledCatalogIdsForActiveProfile() suspend function and filter getDefaultCatalogConfigs() to exclude hidden preinstalled catalogs.

val hiddenForSkeleton = runCatching {
    catalogRepository.getHiddenPreinstalledCatalogIdsForActiveProfile().toSet()
}.getOrDefault(emptySet())
val skeletonDefaults = mediaRepository.getDefaultCatalogConfigs()
    .filterNot { cfg -> cfg.isPreinstalled && cfg.id in hiddenForSkeleton }

Wrapped in runCatching so a DataStore read failure falls back to the old behavior rather than breaking the home load entirely.

Why this is safe

  • Single DataStore read: getHiddenPreinstalledCatalogIdsForActiveProfile() is one context.settingsDataStore.data.first() + a Gson decode — microseconds of cost on a path that already awaits a much longer sequence of network/catalog calls.
  • Same function used elsewhere: CatalogRepository.readCatalogsFromPrefs (line 823-831), CloudSyncRepository.pushToCloud (line 241-246), and CloudSyncRepository.applyCloudPayload (line 446) all use identical filter logic. This PR just applies the same filter one layer up for the skeleton.
  • Only filters preinstalled rows: filterNot { cfg.isPreinstalled && cfg.id in hidden } matches the existing filter at CatalogRepository.kt:831, so custom user-added catalogs are never removed by this code path (they aren't in the default list anyway).
  • No migration needed: the hidden set was already populated by the existing delete flow and cloud sync; this PR just reads it from an additional call site.

Test plan

  • Delete a preinstalled catalog (e.g. "Trending in Anime").
  • Kill the app.
  • Relaunch → verify the catalog does not flash into the home skeleton at any point during load.
  • Delete a catalog, then navigate away from Home and back → verify no flash.
  • Re-enable the catalog from Settings → verify it comes back on next home load.

HomeViewModel.loadHomeData built its "early skeleton" row list directly
from mediaRepository.getDefaultCatalogConfigs(), which is the unfiltered
set of all 26 preinstalled catalogs. The real filtered list (which
correctly respects the hidden_preinstalled_catalogs DataStore key) was
loaded a few lines later, but in the meantime users saw their deleted
catalogs reappear as loading skeletons for 1-3 seconds. On cold launches
or slow networks the flash lasted long enough that users thought the
delete never took — matching the exact symptom reported in #71 (and the
duplicate #74 we already closed).

The persistence layer was always correct: removeCustomCatalog adds the id
to a hidden set, ensurePreinstalledDefaults filters it out, and the cloud
sync snapshot/restore both carry the hidden set. Only the skeleton path
was bypassing all of that.

Fix: read the active-profile hidden set via the existing
catalogRepository.getHiddenPreinstalledCatalogIdsForActiveProfile() suspend
function (single DataStore .first() read, negligible cost) and filter
getDefaultCatalogConfigs() before building the skeleton. Wrapped in
runCatching so a DataStore read failure falls back to the old behavior
instead of breaking the home load.

Closes #71
@ProdigyV21
ProdigyV21 merged commit 7377b53 into main Apr 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Catalogs can't be removed

1 participant